<?php

namespace Core\lib;

use Swoole\Coroutine\Channel;

abstract class DbPool
{
    private $min;
    private $max;
    private $count;
    private $isDelTime = 10;
    /**
     * @var Channel
     */
    private $conns;

    /**
     * DbPool constructor.
     * @param $min
     * @param $max
     * @param $isDelTime
     */
    public function __construct($min = 5, $max = 10, $isDelTime = 10)
    {
        $this->min = $min;
        $this->max = $max;
        $this->isDelTime = $isDelTime;
        $this->conns = new Channel($this->max);
    }

    /**
     * 实现DB
     * @return mixed
     */
    abstract function newDb();

    /**
     * 初始化 连接池
     */
    public function init()
    {
        for ($i = 0; $i < $this->min; $i++) {
            $this->addDBToPool();
        }
//        \Swoole\Timer::tick(2000, function () {
//            $this->cleanPool();
//        });
    }

    /**
     * 添加DB连接进连接池
     */
    protected function addDBToPool()
    {
        try {
            $this->count++;
            $db = $this->newDb();
            if (!$db) {
                throw new \Exception("创建DB对象失败");
            }
            $class = new \stdClass();
            $class->usedTime = time();
            $class->db = $db;
            $this->conns->push($class);
        } catch (\Exception $exception) {
            $this->count--;
        }
    }

    /**
     * 取出一个连接
     * @return mixed
     */
    public function getConnect()
    {
        $getObject = false;
        if ($this->conns->isEmpty()) {
            if ($this->count < $this->max) {
                $this->addDBToPool();
                $getObject = $this->conns->pop();
            } else {
                $getObject = $this->conns->pop(5);
            }
        } else {
            $getObject = $this->conns->pop();
        }
        if ($getObject) {
            $getObject->usedTime = time();
        }
        return $getObject;
    }

    /**
     * 将连接返回 channel
     * @param $conn
     */
    public function close($conn)
    {
        if ($conn) {
            $this->conns->push($conn);
        }
    }

    /**
     * 清理闲置DB连接
     */
    protected function cleanPool()
    {
        $len = $this->conns->length();
        if ($len <= $this->min || $len <= intval($this->max * 0.6)) {
            return;
        }
        echo "清理DB连接池" . PHP_EOL;
        $db_back = [];
        while (true) {
            if ($this->conns->isEmpty()) {
                break;
            }
            $obj = $this->conns->pop(0.1);
            //当前连接总数 大于最小连接数 且 当前连接的空闲时间超过设置 则不回收
            if ($this->count > $this->min && (time() - $obj->usedTime) > $this->isDelTime) {
                $this->count--;
            } else {
                $db_back[] = $obj;
            }
        }
        foreach ($db_back as $value) {
            $this->conns->push($value);
        }
        echo "DB总连接数:" . $this->count . PHP_EOL;
        echo "DB连接数:" . count($db_back) . PHP_EOL;
    }

}
